import numpy as np
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA
from sklearn.manifold import Isomap, LocallyLinearEmbedding, SpectralEmbedding, TSNE
from sklearn.datasets import fetch_openml
import seaborn as sns
from sklearn.preprocessing import StandardScaler

# 加载MNIST数据集
print("正在加载MNIST数据集...")
mnist = fetch_openml('mnist_784', version=1, parser='auto')
X = mnist.data
y = mnist.target.astype(int)

# 标准化数据
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

# 为了加速计算，只使用部分样本
n_samples = 2000
X_sample = X_scaled[:n_samples]
y_sample = y[:n_samples]


# 1. 显示原始图像
def plot_original_images(X, y):
    plt.figure(figsize=(10, 6))
    for i in range(10):
        plt.subplot(2, 5, i + 1)
        # 找到对应数字的第一个样本
        idx = np.where(y == i)[0][0]
        # 重塑为28x28的图像
        img = X[idx].reshape(28, 28)
        plt.imshow(img, cmap='gray')
        plt.title(f'数字 {i}')
        plt.axis('off')
    plt.tight_layout()
    plt.show()


# 2. 可视化PCA转换后的特征数据
def plot_pca_features(X, y):
    # 使用PCA降维到20个特征
    pca = PCA(n_components=20)
    X_pca = pca.fit_transform(X)

    # 可视化前两个主成分
    plt.figure(figsize=(10, 8))
    plt.scatter(X_pca[:, 0], X_pca[:, 1], c=y, cmap='viridis', s=10, alpha=0.8)
    plt.colorbar(label='数字')
    plt.title('PCA主成分分析 (前两个主成分)')
    plt.xlabel('主成分1')
    plt.ylabel('主成分2')
    plt.show()

    # 可视化解释方差比
    plt.figure(figsize=(10, 6))
    plt.bar(range(1, 21), pca.explained_variance_ratio_, alpha=0.8)
    plt.step(range(1, 21), np.cumsum(pca.explained_variance_ratio_), where='mid', color='red')
    plt.axhline(y=0.9, color='g', linestyle='--')
    plt.title('PCA解释方差比')
    plt.xlabel('主成分')
    plt.ylabel('解释方差比')
    plt.legend(['累积解释方差比', '90%阈值', '单个解释方差比'])
    plt.show()


# 3. 使用不同的降维方法并可视化
def plot_dimensionality_reduction(X, y):
    # 定义降维方法
    methods = {
        'PCA': PCA(n_components=2),
        'Isomap': Isomap(n_components=2, n_neighbors=10),
        'LLE': LocallyLinearEmbedding(n_components=2, n_neighbors=10),
        'LE': SpectralEmbedding(n_components=2, n_neighbors=10),
        't-SNE': TSNE(n_components=2, random_state=42)
    }

    # 创建子图
    fig, axes = plt.subplots(2, 3, figsize=(18, 12))
    axes = axes.flatten()

    # 对每个方法进行降维和可视化
    for i, (name, method) in enumerate(methods.items()):
        print(f"正在应用 {name} 降维...")
        X_reduced = method.fit_transform(X)

        # 可视化
        scatter = axes[i].scatter(X_reduced[:, 0], X_reduced[:, 1], c=y, cmap='viridis', s=10, alpha=0.8)
        axes[i].set_title(f'{name} 降维')
        axes[i].set_xlabel('维度 1')
        axes[i].set_ylabel('维度 2')
        fig.colorbar(scatter, ax=axes[i], label='数字')

    # 隐藏最后一个空的子图
    axes[-1].axis('off')

    plt.tight_layout()
    plt.show()


# 执行可视化
print("显示原始图像...")
plot_original_images(X_sample, y_sample)

print("显示PCA转换后的特征数据...")
plot_pca_features(X_sample, y_sample)

print("应用不同的降维方法并可视化...")
plot_dimensionality_reduction(X_sample, y_sample)
